package main.java.LeetCode.ClassicalAlgorithm.Queue.Impl;

import main.java.LeetCode.ClassicalAlgorithm.Queue.Queue;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class LockedBlockQueue<E> extends ReentrantLock implements Queue<E> {

    private final List<E> list;
    private final int cap;

    private final Condition isFull = newCondition();
    private final Condition isEmpty = newCondition();

    public LockedBlockQueue(int cap,List<E> list){
        this.cap = cap;
        this.list = list;
    }

    public LockedBlockQueue(int cap){
        this(cap,new ArrayList<>());
    }
    @Override
    public E get() throws InterruptedException {
        E e = null;
        if(!tryLock())
            return e;

        try{
            if(list.isEmpty())
                return e;
            e = list.remove(0);
            isFull.signal();
            return e;
        }finally {
            unlock();
        }
    }

    @Override
    public boolean set(E e) {
        lock();
        try {
            if (list.size() >= cap)
                return false;
            list.add(e);
            isEmpty.signal();
            return true;
        } finally {
            unlock();
        }
    }

    @Override
    public E get(long timeout, TimeUnit unit) {
        long nanos = unit.toNanos(timeout);
        E e = null;
        lock();
        try {
            if (list.isEmpty()) {
                nanos = isEmpty.awaitNanos(nanos);
                if(nanos<0)
                    return e;
            }
            if(list.isEmpty())
                return e;
            e = list.remove(0);
            isFull.signal();
        }catch (InterruptedException ignored){
        } finally{
            unlock();
        }
        return e;
    }

    @Override
    public boolean offer(E e) {
        if(!tryLock())
            return false;

        try {
            if (list.size() >= cap)
                return false;
            list.add(e);
            isEmpty.signal();
            return true;
        }finally {
            unlock();
        }
    }

    @Override
    public int size() {
        return this.cap;
    }
}
